﻿using InterLock.Common;
using InterLock.Equipmet;
using InterLock.Helper;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using static System.Convert;

namespace InterLock.Algorithm
{
    public class StationMap
    {

        private static List<Equipment> list = CreateStationMapHelper.CreateStationMap();
        private List<Equipment> listEquipment = new List<Equipment>();   //储存进路上的设备
        private List<List<Equipment>> listPath = new List<List<Equipment>>();       //储存进路
        private SearchAlgorithm sa = new SearchAlgorithm();

        private bool m_Begin = false;                              //用于判断始端按钮是否按下

        private Equipment beginEquipment;        //进路的始端设备
        private Equipment endEquipment;          //进路的终端设备

        public bool IsDonw { get; set; }       //判断设备按钮是否被按下

        public void Show()
        {
            foreach (var eq in list)
            {

                TxtHelper.WriteTxt($"Name:{eq.Name}、L:{eq.LZN}、R:{eq.RZN}、W:{eq.WGN}");
            }
        }

        /// <summary>
        /// 设备按钮按下
        /// </summary>
        /// <param name="eq"></param>
        /// <param name="nowP"></param>
        /// <param name="cmd"></param>
        public void ButtonDown(Point nowP, ref int cmd)
        {
            foreach (var p in list)
            {
                if (p.Region.Contains(nowP))
                {
                    IsDonw = true;
                    if (p.EquipmentType == EquipmentType.Signal)
                    {
                        switch (cmd)
                        {
                            case 1:
                                if (!m_Begin)
                                {
                                    beginEquipment = p;
                                    m_Begin = true;
                                    MessageBox.Show($"({p.Name})-始端确认！", "提示！");
                                }
                                else
                                {
                                    if (beginEquipment == p)
                                    {
                                        m_Begin = false;
                                        MessageBox.Show("始终端按钮不可为同一按钮！", "警告！");
                                    }
                                    else
                                    {
                                        endEquipment = p;
                                        m_Begin = false;
                                        MessageBox.Show($"({p.Name})-终端确认！", "提示！");
                                        ExcuteSearchPath();
                                    }
                                }
                                cmd = 1;
                                break;
                            case 2:
                                RouteCancel(p);
                                cmd = 1;
                                break;
                        }
                    }
                    else if (p.EquipmentType == EquipmentType.Track)
                    {
                        switch (cmd)
                        {
                            case 3:
                                TrackOccupied(p);
                                cmd = 1;
                                break;
                            case 4:
                                TrackClear(p);
                                cmd = 1;
                                break;
                        }
                    }
                    else if (p.EquipmentType == EquipmentType.Turnout)
                    {
                        switch (cmd)
                        {
                            case 5:
                                TrunoutNormal(p);
                                cmd = 1;
                                break;
                            case 6:
                                TurnoutReverse(p);
                                cmd = 1;
                                break;
                        }
                    }
                }
            }

        }

        /// <summary>
        /// 绘制站场图
        /// </summary>
        /// <param name="g"></param>
        public void DrawMap(Graphics g)
        {
            var sinal = list.Where(s => s.EquipmentType == EquipmentType.Signal).ToList();
            var track = list.Where(s => s.EquipmentType == EquipmentType.Track).ToList();
            var turnout = list.Where(s => s.EquipmentType == EquipmentType.Turnout).ToList();

            //按图层顺序绘制
            sinal.ForEach(s => s.Draw(g));
            track.ForEach(s => s.Draw(g));
            turnout.ForEach(s => s.Draw(g));
        }

        private void ExcuteSearchPath()
        {
            EquipmentNode result = sa.GetPath(beginEquipment, endEquipment);

            if (result != null)
            {
                if (!PathConfilictCheck(result, beginEquipment, endEquipment))
                {
                    EquipmentTransition();
                }
                else
                {
                    MessageBox.Show("无法建立敌对进路！", "警告！");
                }
            }
            else
            {
                MessageBox.Show("未找到进路！", "提示！");
            }
        }


        #region 设备冲突检查
        /// <summary>
        /// 
        /// </summary>
        /// <param name="result"></param>
        /// <param name="beginE"></param>
        /// <param name="endE"></param>
        /// <returns></returns>
        private bool PathConfilictCheck(EquipmentNode result, Equipment beginE, Equipment endE)
        {
            EquipmentNode p = result;
            while (p != null)                              //查找父节点 反向储存进路元素
            {
                listEquipment.Add(p.Data);
                p = p.Parent;
            }
            listEquipment.Reverse();                                  //将储存的进路元素反转位置
            if ((endE.Character & ToInt32("0X0002", 16)) != 0)  //判断终端是否为列车信号机
            {
                if (endE.R != null && (endE.Character & ToInt32("0X0020", 16)) != 0 && (endE.Character & ToInt32("0X0008", 16)) != 0)   //判断是否为右向接车进路
                {
                    listEquipment.Add(endE.R);
                }
                else if (endE.L != null && (endE.Character & ToInt32("0X0010", 16)) != 0 && (endE.Character & ToInt32("0X0008", 16)) != 0)  //判断是否为左向接车进路
                {
                    listEquipment.Add(endE.L);
                }
            }
            listEquipment = listEquipment.Distinct().ToList();   //去掉重复值

            if (listEquipment.Count > 0)                                 //敌对进路检查
            {
                foreach (var eq in listEquipment)
                {
                    if (eq.SJ)
                    {
                        listEquipment.Clear();//清空进路
                        return true;
                    }
                }
            }
            return false;
        }
        #endregion



        #region 设备状态转换
        /// <summary>
        /// 设备状态转换
        /// </summary>
        private void EquipmentTransition()
        {
            //将进路上的设备锁闭并将道岔转到规定位置
            listEquipment.ForEach(s =>
            {
                s.SJ = true;
                if ((s.N & ToInt32("0X4000", 16)) != 0 && listEquipment.Contains(s.W))
                {
                    s.FWJ = true;
                }
                else if (s.W != null)
                {
                    s.FWJ = false;
                    s.W.FWJ = false;
                }

            });

            //将信号机设到相应状态
            if ((listEquipment.First().N & ToInt32("0X2000", 16)) != 0 && (listEquipment.First().Character & ToInt32("0X0001", 16)) != 0)    //始端为调车信号机
            {
                listEquipment.First().SignlState = SignlType.dc;
            }
            else if ((listEquipment.First().N & ToInt32("0X2000", 16)) != 0 && (listEquipment.First().Character & ToInt32("0X0002", 16)) != 0)  //始端为列车信号机  
            {
                if ((listEquipment.Last().N & ToInt32("0X2000", 16)) != 0 && (listEquipment.Last().Character & ToInt32("0X0001", 16)) != 0)//终端为调车车信号机  
                {
                    listEquipment.First().SignlState = SignlType.dc;
                }
                else
                {
                    if ((listEquipment.First().Character & ToInt32("0X0004", 16)) != 0)           //始端为进站信号机
                    {
                        //linq查询 判断是否经过道岔反位
                        var result = from eq in listEquipment
                                     where (eq.FWJ == true) && ((eq.N & ToInt32("0X4000", 16)) != 0)  //道岔且反位
                                     select eq;
                        if (result.ToList().Count != 0)
                        {
                            listEquipment.First().SignlState = SignlType.cxj;
                        }
                        else
                        {
                            listEquipment.First().SignlState = SignlType.zxj;
                        }
                    }
                    else
                    {
                        listEquipment.First().SignlState = SignlType.tg;
                    }
                }
            }
            listPath.Add(listEquipment);
            listEquipment = new List<Equipment>();
        }
        #endregion


        /// <summary>
        /// 道岔定位
        /// </summary>
        /// <param name="eq"></param>
        private void TrunoutNormal(Equipment eq)
        {

            if (eq.SJ || eq.W.SJ)
            {
                MessageBox.Show("不可转换！", "提示！");
                return;
            }
            eq.FWJ = false;
            eq.W.FWJ = false;
        }

        /// <summary>
        /// 道岔反位
        /// </summary>
        /// <param name="eq"></param>
        private void TurnoutReverse(Equipment eq)
        {
            if (eq.SJ || eq.W.SJ)
            {
                MessageBox.Show("不可转换！", "提示！");
                return;
            }
            eq.FWJ = true;
            eq.W.FWJ = true;
        }

        /// <summary>
        /// 区段占用
        /// </summary>
        /// <param name="eq"></param>
        private void TrackOccupied(Equipment eq)
        {
            eq.ZYJ = true;
            MessageBox.Show(eq.Name.ToString() + "区段被占用！", "提示！");
        }

        /// <summary>
        /// 区段出清
        /// </summary>
        /// <param name="eq"></param>
        private void TrackClear(Equipment eq)
        {
            if (eq.SJ)
            {
                MessageBox.Show("区段锁闭中，无法出清！", "警告！");
                return;
            }
            eq.ZYJ = false;
            MessageBox.Show(eq.Name.ToString() + "区段已出清！", "提示！");
        }


        /// <summary>
        /// 取消进路
        /// </summary>
        private void RouteCancel(Equipment cancelN)
        {
            var path = listPath.Where(s => s.First() == cancelN).FirstOrDefault();
            path.ForEach(o => { o.SJ = false; o.SignlState = SignlType.normal; });
            listPath.Remove(path);
        }
    }
}
